/*******************************************************************
 * Copyright (C) yel_hb-USTC, 2012                                
 *                                                                  
 * FILE NAME             :  LinearClassifier.cpp                                 
 * PRINCIPAL AUTHOR      :  yel_hb                               
 * MODULE NAME           :  LINEARCLASSIFER                             
 * LANGUAGE              :  C++                                      
 * TARGET ENVIRONMENT    :  windows                                   
 * DATE OF FIRST RELEASE :  2012/12/30                              
 * DESCRIPTION           :  implement the functions defined in .h
 ******************************************************************/

/*
 * Revision log:
 *
 * Created by yel_hb,2012/12/30
 *
 */

#include <cmath>
#include "LinearClassifier.h"
#include "kahansum.h"
#include "utils.h"
#include <iostream>
#include <iomanip>
using namespace std;

LinearClassifier::LinearClassifier ()
{
	this->vn = 0;
	this->eta = 0;
}

LinearClassifier::LinearClassifier ( int n, double e )
{
	this->V = DMVector ( n );
	this->vn = 1;
	this->eta = e;
}

DMVector LinearClassifier::get_V ()
{
	return this->V;
}

double LinearClassifier::get_vn ()
{
	return this->vn;
}

double LinearClassifier::get_eta ()
{
	return this->eta;
}

bool LinearClassifier::classify ( const DMVector& X )
{
	DMVector dx = X;
	if ( tanh ( sighned_dist ( X )) < 0 )
		return false;
	else
		return true;
		
}

void LinearClassifier::update_weights ( const DMVector& X, bool inSide )
{
	int i, size = V.size();
	int t, z;
	KahanSum sum;
	if ( inSide == true )
		t = 1;
	else 
		t = -1;

	double f;
	sum.reset();

	for ( i = 0; i < size; ++i )
	{
		 sum.add ( V.get ( i ) * X.get ( i ) );
	}
	sum.add ( vn );
	f = sum.get_sum();

	if ( classify ( X ) == true )
		z = 1;
	else 
		z = -1;
	
	for ( i = 0; i < size; ++i )
	{
		V.set ( i, V.get ( i ) + eta * ( z - t ) * X.get ( i ) * ( 1 - tanh ( f ) * tanh ( f )));
	}

	vn += eta * ( z - t ) * 1 * ( 1 - tanh ( f ) * tanh ( f ));
}

void LinearClassifier::reset ()
{
	int i, size = V.size();
	double norm;
	DMVector dv;

	for ( i = 0; i < size; ++i )
	{
		dv.set ( i, gaussianNormal());
	}

	norm = dv.norm();
	for ( i = 0; i < size; ++i )
	{
		dv.set ( i, dv.get ( i ) / norm );
	}

	set_weight ( NULL, dv );
}

void LinearClassifier::set_weight ( const DMVector& C, const DMVector& N)
{
	V = N;
	vn = V.norm();
}

double LinearClassifier::sighned_dist ( const DMVector& X )
{
	DMVector dx = X;
	
	int i, size = dx.size();	
	KahanSum sum;
	
	sum.reset();
	for ( i = 0; i < size; ++i )
	{
		sum.add ( V.get ( i ) * dx.get ( i ));
	}
	sum.add ( vn );
	return sum.get_sum();
}

LinearClassifier::~LinearClassifier ()
{
	this->vn = 0;
	this->V = NULL;
	this->eta = 0;
}
